package com.yang.frost.raspberry.shiro;

import com.alibaba.fastjson.JSON;
import com.yang.frost.raspberry.config.properties.ShiroPermissionProperties;
import com.yang.frost.raspberry.config.properties.ShiroProperties;
import com.yang.frost.raspberry.shiro.jwt.JwtCredentialsMatcher;
import com.yang.frost.raspberry.shiro.jwt.JwtFilter;
import com.yang.frost.raspberry.util.IniUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.ShiroException;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.mgt.SessionStorageEvaluator;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.*;

/**
 * @author 10296
 * @date 2020/12/24
 * @Description: Shiro 配置
 */

@Configuration
public class ShiroConfig {


    public static final Logger logger = LoggerFactory.getLogger(ShiroConfig.class);

    /*JWT过滤器名称*/
    public static final String JWT_FILTER_NAME = "jwtFilter";
    /* Shiro过滤器名称 */
    private static final String SHIRO_FILTER_NAME = "shiroFilter";
    /*anon*/
    private static final String ANON = "anon";

    @Autowired
    private ShiroProperties shiroProperties;


    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        shiroFilterFactoryBean.setSecurityManager(securityManager);
        Map<String, Filter> filterMap = getFilterMap();
        shiroFilterFactoryBean.setFilters(filterMap);
        Map<String, String> filterChainMap = getFilterChainDefinitionMap();
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainMap);

        return shiroFilterFactoryBean;
    }


    private Map<String, Filter> getFilterMap() {
        Map<String, Filter> filterMap = new LinkedHashMap<>();
        filterMap.put(JWT_FILTER_NAME, new JwtFilter());
        return filterMap;
    }

    /**
     * Shiro  路径权限配置
     *
     * @return
     */
    private Map<String, String> getFilterChainDefinitionMap() {
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        List<String[]> anonList = shiroProperties.getAnon();
        logger.info("anonList:{}", JSON.toJSONString(anonList));
        if (CollectionUtils.isNotEmpty(anonList)) {
            for (int i = 0; i < anonList.size(); i++) {
                String[] anonArray = anonList.get(i);
                if (ArrayUtils.isNotEmpty(anonArray)) {
                    for (String anonPath : anonArray) {

                        filterChainDefinitionMap.put(anonPath, ANON);
                    }

                }
            }

        }

        //获取ini格式配置
        String definitions = shiroProperties.getFilterChainDefinitions();

        if (StringUtils.isNotEmpty(definitions)) {
            Map<String, String> section = IniUtil.parseIni(definitions);
            logger.info("definitions:{}", JSON.toJSONString(section));
            for (Map.Entry<String, String> entry : section.entrySet()
            ) {
                filterChainDefinitionMap.put(entry.getKey(), entry.getValue());
            }
        }
        //获取自定义权限路径配置集合
        List<ShiroPermissionProperties> permissionProperties = shiroProperties.getPermission();
        logger.info("permissionConfigs:{}", JSON.toJSONString(permissionProperties));
        if (CollectionUtils.isNotEmpty(permissionProperties)) {
            for (ShiroPermissionProperties properties : permissionProperties
            ) {
                String url = properties.getUrl();
                String[] urls = properties.getUrls();
                String permission = properties.getPermission();
                if (StringUtils.isEmpty(url) && ArrayUtils.isEmpty(urls)) {
                    throw new ShiroException("Shiro  Persission Config permission 不能为空！");

                }
                if (StringUtils.isNotEmpty(url)) {
                    filterChainDefinitionMap.put(url, permission);
                }
                if (ArrayUtils.isNotEmpty(urls)) {
                    for (String s : urls
                    ) {
                        filterChainDefinitionMap.put(s, permission);
                    }
                }

            }
        }

        // 如果启用shiro，则设置最后一个设置为JWTFilter，否则全部路径放行
        if (shiroProperties.isEnable()) {
            filterChainDefinitionMap.put("/**", JWT_FILTER_NAME);
        } else {
            filterChainDefinitionMap.put("/**", ANON);
        }

        logger.debug("filterChainMap:{}", JSON.toJSONString(filterChainDefinitionMap));

        // 添加默认的filter
//        Map<String, String> newFilterChainDefinitionMap = new HashMap<>();
        Map<String, String> newFilterChainDefinitionMap = addDefaultFilterDefinition(filterChainDefinitionMap);
        return newFilterChainDefinitionMap;
    }

    private Map<String, String> addDefaultFilterDefinition(Map<String, String> filterChainDefinitionMap) {

        if (MapUtils.isEmpty(filterChainDefinitionMap)) {
            return filterChainDefinitionMap;
        }
        Map<String, String> map = new LinkedHashMap<>();
        for (Map.Entry<String, String> entry : filterChainDefinitionMap.entrySet()) {
            logger.info(entry + "-------------------");
            String key = entry.getKey();
            String value = entry.getValue();
            String definition;
            String[] strings = value.split(",");
            List<String> list = new ArrayList<>();
            list.addAll(Arrays.asList(strings));
            definition = String.join(",", list);
            logger.info(key + ":::::" + definition);
            map.put(key, definition);
        }
        return map;

    }

    @Bean
    public DefaultSubjectDAO subjectDAO() {
        DefaultSubjectDAO defaultSubjectDAO = new DefaultSubjectDAO();
        defaultSubjectDAO.setSessionStorageEvaluator(sessionStorageEvaluator());
        return defaultSubjectDAO;
    }


    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 配置 SecurityManager，并注入 shiroRealm
        securityManager.setRealm(shiroRealm());

        return securityManager;
    }

    @Bean
    public ShiroRealm shiroRealm() {
        // 配置 Realm
        ShiroRealm shiroRealm = new ShiroRealm();
        shiroRealm.setCachingEnabled(false);
        shiroRealm.setCredentialsMatcher(credentialsMatcher());
        return shiroRealm;
    }

    @Bean
    public CredentialsMatcher credentialsMatcher() {
        return new JwtCredentialsMatcher();

    }

    @Bean
    public SessionStorageEvaluator sessionStorageEvaluator() {
        DefaultSessionStorageEvaluator storageEvaluator = new DefaultSessionStorageEvaluator();
        storageEvaluator.setSessionStorageEnabled(false);
        return storageEvaluator;
    }


    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

}



